//
// Created by martin on 4/2/22.
//

#ifndef MUDUO_FTPDATACLIENT_H
#define MUDUO_FTPDATACLIENT_H

#include "FtpResponse.h"
#include "muduo/base/noncopyable.h"
#include "muduo/net/Connector.h"
#include "muduo/net/Callbacks.h"
#include "muduo/base/Atomic.h"

#include <string>

namespace ftp
{

typedef std::shared_ptr<muduo::net::Connector> ConnectorPtr;

/**
 * @brief Ftp Data Client for data connection.
 *
 * One Ftp Data Server per data connection.
 *
 * Warning: Default data port is 20 for PORT mode, not PASV mode. But fixed 20 port is not necessary,
 * you can bind a random port allocated by system.
 *
 * Not thread safe. Must be called in owner IO Loop.
 *
 * @note Used for PORT mode.
 */
class FtpDataClient : muduo::noncopyable
{
public:
	FtpDataClient(muduo::net::EventLoop* loop,
		const muduo::net::InetAddress& serverAddr,
		const std::string& nameArg);
	~FtpDataClient();

	void connect();
	// If you just want to disconnect the connection with the Ftp Data Server,
	// please invoke disconnect()
	void disconnect();
	// Reset connector and close connection socket
	// Watchout: It may re-connect to the Ftp Data Server if it is connected status before invoking stop()
	void stop();

	muduo::net::TcpConnectionPtr connection() const
	{
		return connection_;
	}

	muduo::net::EventLoop* getLoop() const { return loop_; }
	bool retry() const { return retry_; }
	void enableRetry() { retry_ = true; }

	const std::string& name() const
	{
		return name_;
	}

	void setConnectionCallback(muduo::net::ConnectionCallback cb)
	{
		connectionCallback_ = std::move(cb);
	}

	void setMessageCallback(muduo::net::MessageCallback cb)
	{
		messageCallback_ = std::move(cb);
	}

	void setWriteCompleteCallback(muduo::net::WriteCompleteCallback cb)
	{
		writeCompleteCallback_ = std::move(cb);
	}

private:

	void newConnection(int sockfd);
	void removeConnection(const muduo::net::TcpConnectionPtr& conn);

	void onConnection(const muduo::net::TcpConnectionPtr& conn);
	void onMessage(const muduo::net::TcpConnectionPtr& conn,
		muduo::net::Buffer* buffer,
		muduo::Timestamp receiveTime);
	void onWriteComplete(const muduo::net::TcpConnectionPtr& conn);

	muduo::net::EventLoop* loop_;
	ConnectorPtr connector_;
	const std::string name_;
	muduo::net::ConnectionCallback connectionCallback_;
	muduo::net::MessageCallback messageCallback_;
	muduo::net::WriteCompleteCallback writeCompleteCallback_;
	bool retry_;   // atomic
	bool connect_; // atomic, connect status
	static muduo::AtomicInt64 nextConnId_; // unique id for connection
	muduo::net::TcpConnectionPtr connection_;
};

typedef std::shared_ptr<FtpDataClient> FtpDataClientPtr;

} // namespace ftp

#endif //MUDUO_FTPDATACLIENT_H
